package com.example.ecommerce.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.ecommerce.common.exception.BusinessException;
import com.example.ecommerce.dto.MenuDTO;
import com.example.ecommerce.entity.Menu;
import com.example.ecommerce.entity.RoleMenu;
import com.example.ecommerce.mapper.MenuMapper;
import com.example.ecommerce.mapper.RoleMenuMapper;
import com.example.ecommerce.service.MenuService;
import com.example.ecommerce.service.RoleMenuService;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Objects;

@Service
@Transactional(rollbackFor = Exception.class)
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private RoleMenuService roleMenuService;


    @Autowired
    private ModelMapper modelMapper;

    @Override
    public List<MenuDTO> getUserMenus(Long userId) {
        // 查询用户的菜单
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.inSql(Menu::getId, 
                "SELECT menu_id FROM rolemenus WHERE role_id IN " +
                "(SELECT role_id FROM userroles WHERE user_id = " + userId + ")")
            .eq(Menu::getStatus, 1)
            .orderByAsc(Menu::getSort);
            
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        
        // 转换并构建树形结构
        List<MenuDTO> menuDTOs = menus.stream()
                .map(menu -> modelMapper.map(menu, MenuDTO.class))
                .collect(Collectors.toList());
                
        return buildMenuTree(menuDTOs, null);
    }

    @Override
    public MenuDTO getMenuById(Long id) {
        Menu menu = menuMapper.selectById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在");
        }
        
        MenuDTO menuDTO = modelMapper.map(menu, MenuDTO.class);
        
        // 设置父菜单名称
        if (menu.getParentId() != null && menu.getParentId() != 0) {
            Menu parentMenu = menuMapper.selectById(menu.getParentId());
            if (parentMenu != null) {
                menuDTO.setParentTitle(parentMenu.getTitle());
            }
        }
        
        // 设置是否有子菜单
        menuDTO.setHasChildren(countChildren(id) > 0);
        
        return menuDTO;
    }

    @Override
    public List<MenuDTO> getMenuTree() {
        // 查询所有启用的菜单
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getStatus, 1)
                .orderByAsc(Menu::getSort);
                
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        
        // 转换并构建树形结构
        List<MenuDTO> menuDTOs = menus.stream()
                .map(menu -> modelMapper.map(menu, MenuDTO.class))
                .collect(Collectors.toList());

        return buildMenuTree(menuDTOs, 0L);
    }

    @Override
    public MenuDTO createMenu(MenuDTO menuDTO) {
        // 验证父菜单
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0) {
            Menu parentMenu = menuMapper.selectById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父菜单不存在");
            }
        }
        
        // 检查同级菜单名称是否重复
        if (checkNameExists(menuDTO.getTitle(), menuDTO.getParentId(), null)) {
            throw new BusinessException("同级菜单名称已存在");
        }
        
        Menu menu = modelMapper.map(menuDTO, Menu.class);
        menu.setCreatedAt(LocalDateTime.now());
        menu.setUpdatedAt(LocalDateTime.now());
        
        menuMapper.insert(menu);
        
        return getMenuById(menu.getId());
    }

    @Override
    public MenuDTO updateMenu(Long id, MenuDTO menuDTO) {
        Menu existingMenu = menuMapper.selectById(id);
        if (existingMenu == null) {
            throw new BusinessException("菜单不存在");
        }
        
        // 验证父菜单
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0) {
            if (id.equals(menuDTO.getParentId())) {
                throw new BusinessException("不能将菜单设置为自己的子菜单");
            }
            Menu parentMenu = menuMapper.selectById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父菜单不存在");
            }
            // 检查是否将菜单设置为其子菜单的子菜单
            if (isChildMenu(id, menuDTO.getParentId())) {
                throw new BusinessException("不能将菜单设置为其子菜单的子菜单");
            }
        }
        
        // 检查同级菜单名称是否重复
        if (!existingMenu.getTitle().equals(menuDTO.getTitle()) && 
                checkNameExists(menuDTO.getTitle(), menuDTO.getParentId(), id)) {
            throw new BusinessException("同级菜单名称已存在");
        }
        
        Menu menu = modelMapper.map(menuDTO, Menu.class);
        menu.setId(id);
        menu.setUpdatedAt(LocalDateTime.now());
        
        menuMapper.updateById(menu);
        
        return getMenuById(id);
    }

    @Override
    public void deleteMenu(Long id) {
        Menu menu = menuMapper.selectById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在");
        }
        
        // 检查是否有子菜单
        if (countChildren(id) > 0) {
            throw new BusinessException("存在子菜单，无法删除");
        }
        
        // 删除菜单角色关系
        LambdaQueryWrapper<RoleMenu> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.eq(RoleMenu::getMenuId, id);
        roleMenuMapper.delete(roleMenuWrapper);
        
        // 删除菜单
        menuMapper.deleteById(id);
    }

    @Override
    public List<MenuDTO> getMenusByRoleId(Long roleId) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.inSql(Menu::getId, 
                "SELECT menu_id FROM role_menus WHERE role_id = " + roleId)
            .eq(Menu::getStatus, 1)
            .orderByAsc(Menu::getSort);
            
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        
        return menus.stream()
                .map(menu -> modelMapper.map(menu, MenuDTO.class))
                .collect(Collectors.toList());
    }

    @Override
    public void assignMenuToRole(Long roleId, List<Long> menuIds) {
        // 删除原有关系
        LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleMenu::getRoleId, roleId);
        roleMenuMapper.delete(wrapper);
        
        // 批量插入新关系
        if (menuIds != null && !menuIds.isEmpty()) {
            List<RoleMenu> roleMenus = menuIds.stream()
                    .map(menuId -> {
                        RoleMenu roleMenu = new RoleMenu();
                        roleMenu.setRoleId(roleId);
                        roleMenu.setMenuId(menuId);
                        return roleMenu;
                    })
                    .collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenus);
        }
    }

    @Override
    public boolean exists(Long id) {
        return menuMapper.selectById(id) != null;
    }

    @Override
    public List<MenuDTO> getAllEnabledMenus() {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getStatus, 1)
                .orderByAsc(Menu::getSort);
                
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        
        return menus.stream()
                .map(menu -> modelMapper.map(menu, MenuDTO.class))
                .collect(Collectors.toList());
    }

    @Override
    public Integer countChildren(Long parentId) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getParentId, parentId);
        return Math.toIntExact(menuMapper.selectCount(queryWrapper));
    }

    @Override
    public boolean checkPermission(Long userId, String permission) {
        if (StringUtils.isEmpty(permission)) {
            return true;
        }
        
        // 查询用户的所有权限
        List<String> permissions = getUserPermissions(userId);
        return permissions.contains(permission);
    }

    private List<MenuDTO> buildMenuTree(List<MenuDTO> menus, Long parentId) {
        List<MenuDTO> sss=  menus.stream()
                .filter(menu -> Objects.equals(menu.getParentId(), parentId))
                .peek(menu -> {
                    menu.setChildren(buildMenuTree(menus, menu.getId()));
                    menu.setHasChildren(!menu.getChildren().isEmpty());
                })
                .collect(Collectors.toList());
        return sss;
    }

    private boolean checkNameExists(String title, Long parentId, Long excludeId) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getTitle, title)
                .eq(Menu::getParentId, parentId);
                
        if (excludeId != null) {
            queryWrapper.ne(Menu::getId, excludeId);
        }
        
        return menuMapper.selectCount(queryWrapper) > 0;
    }

    private boolean isChildMenu(Long menuId, Long parentId) {
        while (parentId != null && parentId != 0) {
            Menu parent = menuMapper.selectById(parentId);
            if (parent == null) {
                return false;
            }
            if (parent.getId().equals(menuId)) {
                return true;
            }
            parentId = parent.getParentId();
        }
        return false;
    }

    private List<String> getUserPermissions(Long userId) {
        // 查询用户的所有菜单权限
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.inSql(Menu::getId, 
                "SELECT menu_id FROM role_menus WHERE role_id IN " +
                "(SELECT role_id FROM user_roles WHERE user_id = " + userId + ")")
            .eq(Menu::getStatus, 1);
            
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        
        return menus.stream()
                .map(Menu::getPermission)
                .filter(StringUtils::hasText)
                .collect(Collectors.toList());
    }
}